/**
 * 这个类是所有可以触发事件的对象的基类，当一个事件发生时，Publisher就会遍历注册的回调列表
 * 调用每一个事件数据和提供给它相应的事件处理对象。Publisher是sim中大部分对象的基类
 */

interface ISubscriber {
    subscriber: any,
    callback: Function
}

export default class Publisher {

    public messageTypes: any;

    public constructor() {

    }

    public subscribe(message: string, subscriber: any, callback: Function) {
        let subscribers: ISubscriber[] = this.messageTypes[message];
        if (subscribers) {
            if (this.findSubscriber(subscribers, subscriber) !== -1) {
                return;
            }
        } else {
            subscribers = [];
            this.messageTypes[message] = subscribers;
        }
        let aSubscriber: ISubscriber = { subscriber: subscriber, callback: callback };
        subscribers.push(aSubscriber);
    }

    public unsubscribe(message: string, subscriber: any, callback: Function): void {
        if (subscriber.subscriber) {
            let subscribes: ISubscriber[] = this.messageTypes[message];
            if (subscribes) {
                let i: number = this.findSubscriber(subscribes, subscriber);
                if (i !== -1) {
                    this.messageTypes[message].splice(i, 1);
                }
            }
        } else {
            delete this.messageTypes[message];
        }
    }

    public publish(message: string): void {
        let subscribes: ISubscriber[] = this.messageTypes[message];
        if (subscribes) {
            for (let i: number = 0; i < subscribes.length; i++) {
                let args: any[] = [];
                for (let j: number = 0; j < arguments.length - 1; j++) {
                    args.push(arguments[j + 1]);
                }
                subscribes[i].callback.apply(subscribes[i].subscriber, args);
            }
        }
    }

    public findSubscriber(subscribers: ISubscriber[], subscriber: any): number {
        for (let i: number = 0; i < subscribers.length; i++) {
            if (subscribers[i].subscriber === subscriber) {
                return i;
            }
        }
        return -1;
    }
}